import kqueue
import socket
import fcntl
import os
import time

HOST = '127.0.0.1'
PORT = 8000

changelist = []
nchanges = 1
nevents = 20

response = '\r\n'.join(['HTTP/1.1 200 OK', 'Connection: close', 'Content-Type: text/htm', \
'Server: SimepleHTTPServer/1.0', 'Content-Length: 11', 'Content-Type: text/html', \
'Date: Wed, 26 Dec 2007 13:09:35 GMT', '', 'HelloWorld'])

sockets = {}

def unpack(elist):
    buf = []
    for e in elist:
        buf.append(str((e.ident, e.filter, e.flags, e.fflags, e.data)))
    return ''.join(buf)

def register_event(conn):
    '''Register the event for new connection
    '''
    fcntl.fcntl(conn.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
    conn_fd = conn.fileno()
    changelist.append(kqueue.Event(conn_fd, kqueue.EVFILT_READ, kqueue.EV_ADD))
    print 'Register new connection ', conn_fd
    print 'Changelist = ', changelist
    print conn.recv(10)

if __name__ == '__main__':
    # Bind socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock_fd = s.fileno()
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind((HOST, PORT))
    s.listen(5)
    
    # configure non-blocking
    fcntl.fcntl(sock_fd, fcntl.F_SETFL, os.O_NONBLOCK)
    
    # Initialize kqueue
    kq = kqueue.kqueue()
    ev_srv = kqueue.Event(sock_fd, kqueue.EVFILT_READ, kqueue.EV_ADD)
    
    changelist.append(ev_srv)

    print 'Server Started..., FD = ', sock_fd

    while True:
        num, eventlist = kqueue.kevent(kq, changelist, nevents, None)
        changelist = []
        if num == -1:
            print 'Error'
            break
        if num > 0:
            print 'Current Eventlist(%d) = %s' % (len(eventlist), unpack(eventlist))
            for e in eventlist:
                if e.ident == sock_fd:
                    conn, addr = s.accept()
                    sockets[conn.fileno()] = conn
                    print 'Accept new connection from FD = ', conn.fileno(), addr
                    fcntl.fcntl(conn.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
                    ev_conn = kqueue.Event(conn.fileno(), kqueue.EVFILT_READ, kqueue.EV_ADD)
                    changelist.append(ev_conn)
                    nevents += 1
                    print 'Append new event into kqueue'
                elif e.filter == kqueue.EVFILT_READ:
                    print 'Handle request for ', e.ident, e.filter, e.flags, e.fflags, e.data
                    if e.flags & kqueue.EV_ERROR:
                        print 'Error occurs ', e.data
                        # ev_conn = kqueue.Event(e.ident, kqueue.EVFILT_READ, kqueue.EV_DELETE)
                        # changelist.append(ev_conn)
#                    elif e.flags & kqueue.EV_EOF:
#                        print 'Remove event for FD = ', e.ident
#                        print os.read(e.ident, 1024)
#                        nevents -= 1
                    elif e.flags & kqueue.EV_DELETE:
                        print 'Event deleted.'
                    else:
                        try:
                            os.read(e.ident, 1024)
                            os.write(e.ident, response)
                            sockets[e.ident].close()
                        except Exception, ex:
                            print 'Catched Error ', ex
                        print 'Wrote response'
                print '----------'